package cn.tanghom.support.hook;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.unbiz.common.ObjectUtil;
import com.unbiz.common.ReflectionUtil;


public class ModuleManager{
	protected static final Logger logger = LoggerFactory.getLogger(ModuleManager.class);
	
	private static Map<Class<?>,List<AbstractModule<?>>> moduleMap = new HashMap<Class<?>,List<AbstractModule<?>>>();
	
	private final static List<AbstractModule<?>> EMPTY = new LinkedList<AbstractModule<?>>();
	
	private static boolean isSorted = false;	
	
	public static <T extends AbstractModule<?>> void registerModule(Class<?> cls, AbstractModule<?> module){
		List<AbstractModule<?>>  plugins = getModules(cls);
		if(plugins==EMPTY){
			plugins = new LinkedList<AbstractModule<?>>();
			moduleMap.put(cls,plugins);
		}
		plugins.add(module);	
		isSorted = false;
	}
	
	//根据父Module获取子modules
	public static <T extends AbstractModule<?>> List<T> getModulesByType(Class<T> cls){		
		Type t = cls.getGenericSuperclass();
		Class clsz = cls;
		while(!(t instanceof ParameterizedType)){
			clsz = clsz.getSuperclass();
			t = clsz.getGenericSuperclass();
		}
		Type[] params = ((ParameterizedType) t).getActualTypeArguments();		
		Class<?> ncls = (Class<?>) params[0];
		List<T>  plugins = getModules(ncls);		
		return (List<T>)plugins;
	}	
	
	
	@SuppressWarnings("unchecked")
	public static <T extends AbstractModule<?>> List<T> getModules(Class<?> cls){
		List<AbstractModule<?>>  plugins = moduleMap.get(cls);
		if(plugins==null){
			return  (List<T>)EMPTY;
		}		
		return (List<T>)plugins;
	}	
	
	public static List<Object>  callAll(Class<?> cls, String method, Object... params){
		List<AbstractModule<?>>  plugins = getModules(cls);		
		List<Object> results = new ArrayList<Object>(plugins.size());
		for(AbstractModule<?> plugin: plugins){
			try{
				if(plugin.status>0 && plugin.hook(method, params)){
					Object result = ReflectionUtil.invokeMethod(plugin, method, params);
					results.add(result);
				}
			}
			catch(Exception e){			
				plugin.handleError(method,e);
			}
		}
		return results;
	}	
	
	public static boolean invokeAll(Class<?> cls, String method, Object... params){
		List<AbstractModule<?>>  plugins = getModules(cls);	
		boolean rv = true;
		for(AbstractModule<?> plugin: plugins){
			try{
				if(plugin.status>0 && plugin.hook(method, params)){
					ReflectionUtil.invokeMethod(plugin,method, params);				
				}
			}
			catch(Exception e){				
				plugin.handleError(method,e);
				rv = false;
			}
		}
		return rv;
	}

	public static void initModules(){
		for(List<AbstractModule<?>> modules: moduleMap.values()){			
			Collections.sort(modules);				
			for(AbstractModule<?> module:modules){
				module.init();
			}			
			isSorted = true;
		}		
	}	
}
